#include "CharacterDataSet.h"
#include "base/core/hash.h"
#include "Common/TableDefine.h"
#include "Common/TableData/EquipEquipCfg.h"

CharacterDataSet::CharacterDataSet()
{}

CharacterDataSet::~CharacterDataSet()
{}

bool CharacterDataSet::Init()
{
    return true;
}

bool CharacterDataSet::UnInit()
{
	auto it = m_charMap.begin();
	for (; it != m_charMap.end(); ++it)
	{
        delete it->second;
        it->second = NULL;
    }
	m_charMap.clear();
	m_charIdsMap.clear();
    return true;
}

bool CharacterDataSet::AddCharacterData(const std::string& channelId, const std::string& userId, const CharacterDBInfo& charInfo)
{
    bool result = false;
    uint64_t key = _GetKey(channelId, userId);
	CharIDType charId = charInfo.charid();
	CharacterDBInfo* charCopy = NULL;
    MMOLOG_PROCESS_ERROR(charId != 0);
    {
		auto it = m_charMap.find(charId);
		if (it != m_charMap.end())
		{
            delete it->second;
			m_charMap.erase(charId);
        }
    }
	charCopy = new CharacterDBInfo;
	charCopy->CopyFrom(charInfo);

	m_charMap[charId] = charCopy;
	m_charIdsMap[key].insert(charId);

    result = true;
Exit0:
    return result;
}

bool CharacterDataSet::DelCharacterData(const std::string& channelId, const std::string& userId, CharIDType charId)
{
    uint64_t key = _GetKey(channelId, userId);
	auto it1 = m_charIdsMap.find(key);
	if (it1 != m_charIdsMap.end()) 
	{
		it1->second.erase(charId);
        if (it1->second.size() == 0) 
		{
			m_charIdsMap.erase(it1);
        }
    }
	auto it2 = m_charMap.find(charId);
	if (it2 != m_charMap.end()) 
	{
        delete it2->second;
		m_charMap.erase(it2);
    }

    return true;
}

CharacterDBInfo* CharacterDataSet::GetCharacterData(CharIDType charId)
{
	auto it = m_charMap.find(charId);
	if (it != m_charMap.end()) 
	{
        return it->second;
    }
    return NULL;
}

bool CharacterDataSet::ClearCharacterData(const std::string& channelId, const std::string& userId)
{
    uint64_t key = _GetKey(channelId, userId);
	auto it = m_charIdsMap.find(key);
	MMO_RET_FALSE(it != m_charIdsMap.end());
	std::set<CharIDType>& idSet = it->second;
	for (auto itSet = idSet.begin(); itSet != idSet.end(); ++itSet)
	{
		CharIDType charId = *itSet;
		auto itChar = m_charMap.find(charId);
		if (itChar != m_charMap.end())
		{
			delete itChar->second;
			m_charMap.erase(itChar);
        }
    }
	m_charIdsMap.erase(it);
    return true;
}

bool CharacterDataSet::CheckHaveCharacter(const std::string& channelId, const std::string& userId, CharIDType charId)
{
    uint64_t key = _GetKey(channelId, userId);
	auto it = m_charIdsMap.find(key);
	MMO_RET_FALSE(it != m_charIdsMap.end());
	if (it->second.find(charId) != it->second.end()) 
	{
        return true;
    }
    return false;
}

uint32_t CharacterDataSet::GetCharacterCount(const std::string& channelId, const std::string& userId)
{
    uint64_t key = _GetKey(channelId, userId);
	auto it = m_charIdsMap.find(key);
	if (it != m_charIdsMap.end()) 
	{
        return (uint32_t)it->second.size();
    }
    return 0;
}

bool CharacterDataSet::GetCharacterSimpleInfoList(const std::string& channelId, const std::string& userId, ClientCharacterListResponse& charSimpleInfoList)
{
	uint64_t key = _GetKey(channelId, userId);
	auto it = m_charIdsMap.find(key);
	MMO_RET_FALSE(it != m_charIdsMap.end());
	std::set<CharIDType>& idSet = it->second;
	auto itSet = idSet.begin();
	CharacterDBSimpleInfo* simpleInfo = NULL;
	for (; itSet != idSet.end(); ++itSet) 
	{
		simpleInfo = charSimpleInfoList.add_charinfolist();
		GetCharacterSimpleInfo(*itSet, *simpleInfo);
	}
	return true;
}

bool CharacterDataSet::GetCharacterSimpleInfo(CharIDType charId, CharacterDBSimpleInfo& charSimpleInfo)
{
	bool result = false;
	CharacterDBInfo* charInfo = NULL;
	auto it = m_charMap.find(charId);
	MMOLOG_PROCESS_ERROR(it != m_charMap.end());
	charInfo = it->second;
	MMOLOG_PROCESS_ERROR(charInfo != NULL);
	{
		const CharacterDBBaseInfo& baseInfo = charInfo->basedata();
		charSimpleInfo.set_charid(charId);
		charSimpleInfo.set_name(baseInfo.name());
		charSimpleInfo.set_sex(baseInfo.sex());
		charSimpleInfo.set_prof(baseInfo.prof());
		charSimpleInfo.set_level(baseInfo.level());
		charSimpleInfo.set_race(baseInfo.race());
		charSimpleInfo.set_exp(baseInfo.exp());
		charSimpleInfo.set_hp(baseInfo.hp());
		charSimpleInfo.set_fightpower(baseInfo.fightpower());
		charSimpleInfo.set_official(baseInfo.official());
		charSimpleInfo.set_knight(baseInfo.knight());
		charSimpleInfo.set_camp(baseInfo.camp());
		charSimpleInfo.set_contribute(baseInfo.contribute());
		charSimpleInfo.set_contricoin(baseInfo.contricoin());
		charSimpleInfo.set_prestige(baseInfo.prestige());
		charSimpleInfo.set_charm(baseInfo.charm());

		CharFacadeProto *facade = charSimpleInfo.mutable_facade();
		MMOLOG_PROCESS_ERROR(facade != NULL);

		const CharacterDBEquipData &protoEquip = charInfo->equipdata();
		uint16_t nequipSize = (uint16_t)protoEquip.equip_size();
		for (uint16_t k = 0; k < nequipSize; ++k)
		{
			const ItemProtoInfo &protoItem = protoEquip.equip(k);
			if (EEquipPos_clothes == protoItem.index())
				facade->set_clothes_id(protoItem.item_id());
			else if (EEquipPos_weapon == protoItem.index())
				facade->set_weapon_id(protoItem.item_id());
			else if (EEquipPos_wing == protoItem.index())
				facade->set_wing_id(protoItem.item_id());
		}

		uint16_t nfashionSize = (uint16_t)protoEquip.fashion_size();
		for (uint16_t i = 0; i < nfashionSize; ++i)
		{
			const FashionProtoInfo &fashionProto = protoEquip.fashion(i);
			if (fashionProto.is_dress())
				facade->set_fashion_id(fashionProto.fashion_id());
		}

		facade->set_rune_dw_id(protoEquip.dw_rune_id());
		facade->set_rune_yk_id(protoEquip.yk_rune_id());
	}
	result = true;
Exit0:
	return result;
}

uint64_t CharacterDataSet::_GetKey(const std::string& channelId, const std::string& userId)
{
    return BKDRHashForString64Bit(channelId.c_str(), userId.c_str());
}
